//
//  UserAccountViewModel.swift
//  xinlangweibo
//
//  Created by yangshuo on 15/12/1.
//  Copyright © 2015年 yangshuo. All rights reserved.
//

import Foundation
//viewModel最重要的目的为控制器瘦身!
//用户账号视图模型-没有父类
/**模型通常继承自NSObject -> 可以使用KVC设置属性,简化对象构造
   如果没有父类,所有内容都要从头创建,量级更轻(因为没有预先创建好的父类)
  视图模型的作用:'封装业务逻辑',通常没有复制的属性
*/

class UserAccountViewModel{
    //创建一个单例,避免沙盒重复加载
    static let sharedUserAccount = UserAccountViewModel()
    
    var account: UserAccount?
    
    //用户登录标记
    var userLoad: Bool{
        //用户登录成功需满足两个条件
        //1.token不为空
        //2.token为过期
        return account?.access_token != nil && !isExpired
    }
    
    //token在所有的网络方法中,除了用户登录环节外,都需要使用token
    //抽取viewmodel的token参数(让调用方不再关系token),不需要作为loadUserInfo参数,而是单独作为一个计算性属性
     //实现思路:1.设置没有过期的token
    //2.增加token的字典处理
    //3.调整网路方法
    //首先创建一个计算性属性token->判断是否过期,然后传到network中,进行字典处理->如果传过去的token是有效的,那么就将返回token字典(包含access_token键值对),然后在传递给拥有access参数的loadUserInfo方法中,先守卫一下token字典是否为空,如果为空报错,如果不为空,将token字典传给paramentes,然后在loadUserInfo方法中,就可以取消该方法的access参数
    var access_token: String?{//1.设置没有过期的token
        if !isExpired{
            return account?.access_token
        }else{
            return nil
        }
    }
    
    var avatarUrl: NSURL{
       //如果account.avatar_large为空,返回"",因为必须传回一个NSURl,使用!强制解包
        return NSURL(string: account?.avatar_large ?? "")!
    }
    //归档保存路径-计算型属性(类似于有返回值的函数,可以让调用的时候,语义更清晰)
    private var accountPath: String{
        let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
        return (path as NSString).stringByAppendingPathComponent("account.plist")
    }
    
    //判断用户是否过期
    private var isExpired: Bool{
        
        //对用户的过期日期与当前日期进行比较
        //如果用户的过期日期小与当前日期,即判断用户过期,否则用户未过期
        
        //过期测试
        //account?.expires_date = NSDate(timeIntervalSinceNow: -3600)

        //双问号格式,如果account为nil,不再进行判断,account不为空,expires_date为空,不继续判断
       if account?.expires_date?.compare(NSDate()) == NSComparisonResult.OrderedDescending{
                    return false
        }
        return true
    }
    //如果不设置一个单例,每一个控制器都会调实例化构造函数
    //构造函数 ->私有化,会要求外部只能通过单例常量访问,而不能()实例化
   private init(){
        //归档将->将对象转成二进制数据,存储到沙盒中
        //解档->将二进制文件转成对象,传到模型中等待调用
        //从沙盒中解档数据,恢复当前数据,传递到模型中
    account = NSKeyedUnarchiver.unarchiveObjectWithFile(accountPath) as? UserAccount
        
        if isExpired {
          //  print("已经过期")
            account = nil
        }
   //      print(account)
    }
}
//viewmodel,封装网络方法
// MARK: - 用户账户相关的网络方法(为控制器瘦身)
//控制器只负责发送授权码
//加载token与获取用户账户中account相关的数据
/*
代码重构的步骤
1. 新方法
2. 粘贴代码
3. 根据上下文调整参数和返回值
4. 移动其他`子`方法
*/

extension UserAccountViewModel{
    //加载token
    func loadAccessToken(code: String, finish:(isSuccessed: Bool)->()){
        //加载accessToken,(与block回调很像!)
        NetWork.sharedNetWork.loadAccessToken(code, successFinish: { (success) -> () in
            //输出结果-在swift中任何的anyObject在使用前必须转换类型(因为anyObject是任何类型,不能做任何计算)
            
            //token字典转模型,在viewmodel的闭包中使用self.account来接受模型数据
            self.account = UserAccount(dict: success as![String: AnyObject] )
            //闭包中需要写self!
            //闭包self只能调用在同一个extension中的自定义函数方法
            self.loadUserInfo(self.account!,finish: finish)
            }) { (error) -> () in
                print("~~~出错了~~~\(error)")
                finish(isSuccessed: false)
                return
        }
        
    }


private func loadUserInfo(account:UserAccount, finish:(isSuccessed: Bool)->()){
    //因为uid,与access_token的两个参数是必要的,所以需要进行强行解包!account.uid!
    NetWork.sharedNetWork.loadUserInfo(account.uid!, successFinish: { (success) -> () in
        // 提示：如果使用 if let / guard let 统统使用 `?`
        // 作了两个判断
        // 1. result 一定有内容
        // 2. 一定是字典
        
        guard let dict = success as?[String: AnyObject] else{
            print("格式错误")
            return
        }
        //为数据模型中的screen_name与avatar_large赋值
        //因为字典类型的值是[String: AnyObject],所以使用as转换成string
        account.screen_name = dict["screen_name"] as? String
        account.avatar_large = dict["avatar_large"] as? String
        
        //归档&解档->外部调用,内部实现
        //运行archiveRootObject时系统默认调用对象的encodeWithCoder归档方法
        NSKeyedArchiver.archiveRootObject(account, toFile: self.accountPath)
        print(self.accountPath)
        //保存对象(account)
   //     account.saveUserAccount()
       // print(account)
        //如果正确告知父类
        return finish(isSuccessed: true)
        }) { (error) -> () in
            print("~~出错了~~\(error)")
            finish(isSuccessed: false)
            return
    }
}
}
